home *** CD-ROM | disk | FTP | other *** search
- /*
- #### # # # #
- # # # # # The FreeWare C library for
- # # ## ### # # # # ### RISC OS machines
- # # # # # # # # # # # ___________________________________
- # # #### ### ## # # # #
- # # # # # # # # # # Please refer to the accompanying
- #### ### #### # # ##### # ### documentation for conditions of use
- ________________________________________________________________________
-
- File: Save.Save.c
- Author: Copyright © 1994 Julian Smith and Jason Howat
- Version: 1.02 (18 Jun 1994)
- Purpose: Automated handling of save-as window
- Mods: 13-Jun-1994 - JPS - Added support for filetypes
- 18-Jun-1994 - JDH - Changed sense of value returned by
- save_filesaver to be in line with rest of DeskLib.
- save_filsaver uses filename instead of stream. Tidied code
- to use core routines and proper DeskLib conventions. Added
- Save__KeyHandler to check for RETURN key in text icon. For
- a RETURN key or OK click, added check that filename isn't
- just a leafname. Changed Save__DragIconClickHandler to use
- Icon_StartSolidDrag. Changed several routines to make
- messages in their own blocks -- they used to corrupt
- event_lastevent. In Save__MessageHandler the initial
- reference check excludes unacknowledged messages that were
- returned.
-
- 04 Nov 1994 Modified to work as a Shell sublibrary - JPS.
- This is because DeskLib hasn't been released with Save 1.02 yet, but
- Shell requires Save 1.02.
- */
-
- #include "DeskLib:Event.h"
- #include "DeskLib:WimpSWIs.h"
- #include "DeskLib:Icon.h"
- #include "DeskLib:Keycodes.h"
- #include "DeskLib:Error.h"
- #include "DeskLib:Str.h"
- #include "Desklib:File.h"
-
- #include "Shell.Save102.h"
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
-
- void Shell_Save102_SetFiletype(Shell_Save102_saveblock *saveblock, int filetype)
- {
- saveblock->filetype = filetype;
- Icon_FileIcon(saveblock->window, saveblock->dragsprite, filetype);
- }
-
-
-
- static void Shell_Save102__CleanIconText(window_handle window, icon_handle icon)
- /* used to clean up writable-icon text - these seem to be
- * terminated by '\n', which is no use to <string.h> functions.
- */
- {
- icon_block iconblock;
-
- Wimp_GetIconState(window, icon, &iconblock);
- Str_MakeASCIIZ(iconblock.data.indirecttext.buffer,
- iconblock.data.indirecttext.bufflen-1);
- }
-
-
- static void Shell_Save102__ResetSaveBlock(Shell_Save102_saveblock *saveblock)
- {
- saveblock->ram_progress = 0;
- saveblock->last_message_ref = -1;
- saveblock->flags.data.we_are_dragging = FALSE;
- }
-
-
- static BOOL Shell_Save102__SaveDataToFilename(char *filename, Shell_Save102_saveblock *saveblock)
- {
- BOOL Shell_Save102_ok;
-
- Shell_Save102_ok = saveblock->filesaver(filename, saveblock->ref);
-
- if(Shell_Save102_ok)
- File_SetType(filename, saveblock->filetype);
- else
- saveblock->resulthandler(Shell_Save102_FILESAVERFAILED, saveblock);
-
- return Shell_Save102_ok;
- }
-
-
- static void Shell_Save102__CloseMenuOrSaveWindow(Shell_Save102_saveblock *saveblock)
- /* A save has been completed with 'Select'.
- * If we were part of a menu, close menu.
- * If we were a save window, close this window.
- * If none of the above, our window contains other things, (it might be the
- * main document window with a 'Quick save' icon), so do nothing.
- * The Event_ handlers will be released by Save_CloseHandler and
- * Save_MenusDeletedHandler, so we don't release them here.
- */
- {
- if(saveblock->flags.data.is_menu)
- Wimp_CreateMenu((menu_block *)-1, 0, 0); /* close menu */
-
- if(saveblock->flags.data.is_save_window)
- Wimp_CloseWindow(saveblock->window); /* close window */
- }
-
-
- static BOOL Shell_Save102__OKIconHandler(event_pollblock *event, void *ref)
- {
- icon_block iconblock;
- Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
- char *filename;
-
- Wimp_GetIconState(saveblock->window, saveblock->filenameicon, &iconblock);
- filename = iconblock.data.indirecttext.buffer;
-
- if(LeafName(filename) != filename) /* not just a leafname in icon */
- {
- Shell_Save102__SaveDataToFilename(iconblock.data.indirecttext.buffer, saveblock);
- Shell_Save102__ResetSaveBlock(saveblock);
-
- if((event->type == event_CLICK && event->data.mouse.button.data.select) ||
- event->type == event_KEY)
- Shell_Save102__CloseMenuOrSaveWindow(saveblock);
- }
- else
- Error_Report(0, "To save, drag the icon to a directory display");
-
- return TRUE;
- }
-
-
- static BOOL Shell_Save102__KeyHandler(event_pollblock *event, void *ref)
- {
- if(event->data.key.code == keycode_RETURN)
- return Shell_Save102__OKIconHandler(event, ref);
-
- return FALSE;
- }
-
-
- static BOOL Shell_Save102__CancelIconHandler(event_pollblock *event, void *ref)
- {
- UNUSED_ARG(event);
-
- Shell_Save102__CloseMenuOrSaveWindow((Shell_Save102_saveblock *)ref);
- return TRUE;
- }
-
-
- static BOOL Shell_Save102__DragIconClickHandler(event_pollblock *event, void *ref)
- {
- Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
-
- if(!event->data.mouse.button.data.dragselect &&
- !event->data.mouse.button.data.dragadjust)
- return FALSE;
-
- saveblock->flags.data.quit_after_save =
- event->data.mouse.button.data.dragselect;
-
- saveblock->flags.data.we_are_dragging = TRUE;
-
- Icon_StartSolidDrag(saveblock->window, saveblock->dragsprite);
-
- return TRUE;
- }
-
-
- static BOOL Shell_Save102__UserDragHandler(event_pollblock *event, void *ref)
- {
- Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
- mouse_block ptr;
- message_block msg;
-
- UNUSED_ARG(event);
-
- /* Is the drag nothing to do with the save drag-icon? */
- if(!saveblock->flags.data.we_are_dragging)
- return FALSE;
-
- saveblock->flags.data.we_are_dragging = FALSE;
-
- Wimp_GetPointerInfo(&ptr);
-
- msg.header.size = 80;
- msg.header.yourref = 0;
- msg.header.action = message_DATASAVE;
- msg.data.datasave.window = ptr.window;
- msg.data.datasave.icon = ptr.icon;
- msg.data.datasave.pos = ptr.pos;
- msg.data.datasave.estsize = saveblock->estimatedsize;
- msg.data.datasave.filetype = saveblock->filetype;
-
- strcpy(msg.data.datasave.leafname,
- LeafName(Icon_GetTextPtr(saveblock->window, saveblock->filenameicon)));
-
- Wimp_SendMessage(event_SENDWANTACK, &msg, ptr.window, ptr.icon);
-
- saveblock->last_message_ref = msg.header.myref;
-
- return TRUE;
- }
-
-
- static BOOL Shell_Save102__MenusDeletedOrWindowClosedHandler(event_pollblock *event,
- void *ref)
- {
- Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
-
- /* Don't release handlers when menu/window is closed */
- if(!saveblock->flags.data.release_after)
- return FALSE;
-
- if((event->type == event_SEND && saveblock->flags.data.is_menu &&
- event->data.message.header.action == message_MENUSDELETED) ||
- (event->type == event_CLOSE && saveblock->flags.data.is_save_window))
- {
- Shell_Save102_ReleaseSaveHandlers(ref);
- free(saveblock);
- }
-
- return FALSE;
- }
-
-
- static BOOL Shell_Save102__MessageHandler(event_pollblock *event, void *ref)
- {
- Shell_Save102_saveblock *saveblock = (Shell_Save102_saveblock *)ref;
- message_block *msg = &event->data.message;
-
- if(event->type != event_ACK &&
- msg->header.yourref != saveblock->last_message_ref)
- return FALSE;
- /* we are only interested in replies to our previous messages...
- or unacknowledged messages */
-
- if(msg->header.action == message_DATASAVE)
- {
- /* User has dragged onto useless part of the desktop...
- * This could be our original message_SENDWANTACK being sent to us
- * because the sprite was dragged onto one of *our task's* windows,
- * or a message_ACK sent to us by the WIMP because nobody responded
- * to our original message.
- */
-
- return FALSE; /* the app might want to deal with this
- * message to save into itself.
- */
- }
-
- if(msg->header.action == message_DATASAVEACK)
- {
- BOOL save_ok;
-
- save_ok = Shell_Save102__SaveDataToFilename(msg->data.datasaveack.filename,
- saveblock);
- if(save_ok)
- {
- message_block reply;
-
- memcpy(&reply, msg, sizeof(message_block));
-
- reply.header.action = message_DATALOAD;
- reply.data.dataload.size = 49;
- reply.header.yourref = reply.header.myref;
-
- Wimp_SendMessage(event_SENDWANTACK, &reply, reply.header.sender, 0);
-
- saveblock->last_message_ref = reply.header.myref;
- }
- else
- Shell_Save102__ResetSaveBlock(saveblock);
-
- return TRUE;
- }
-
- if(msg->header.action == message_RAMFETCH)
- {
- /* If we ignore message_RAMFETCH, the receiving task should
- * try again using a transfer through <Wimp$Scrap>.
- */
- int byteswritten;
- BOOL last_ramtransfer;
- message_block reply;
-
- if(saveblock->ramsaver == NULL)
- return TRUE;
-
- byteswritten = (saveblock->ramsaver)(event_taskhandle, saveblock->ref,
- msg->header.sender,
- msg->data.ramfetch.buffer,
- msg->data.ramfetch.buffsize,
- saveblock->ram_progress);
-
- last_ramtransfer = byteswritten < msg->data.ramfetch.buffsize;
- saveblock->ram_progress += byteswritten;
-
- if(byteswritten < 0)
- {
- (saveblock->resulthandler)(Shell_Save102_RAMSAVERFAILED, saveblock);
- Shell_Save102__ResetSaveBlock(saveblock);
- return TRUE;
- }
-
- memcpy(&reply, msg, sizeof(message_block));
- reply.header.yourref = reply.header.myref;
- reply.header.action = message_RAMTRANSMIT;
- reply.data.ramtransmit.byteswritten = byteswritten;
-
- Wimp_SendMessage((last_ramtransfer) ? event_SEND : event_SENDWANTACK,
- &reply, reply.header.sender, 0);
-
- saveblock->last_message_ref = reply.header.myref;
-
- if(last_ramtransfer)
- {
- Shell_Save102__ResetSaveBlock(saveblock);
- if(saveblock->flags.data.quit_after_save)
- Shell_Save102__CloseMenuOrSaveWindow(saveblock);
-
- (saveblock->resulthandler)(Shell_Save102_SAVEOK, saveblock->ref);
- }
-
- return TRUE;
- }
-
- if(msg->header.action == message_RAMTRANSMIT)
- {
- /* This is our message being returned to us by the Wimp */
- Shell_Save102__ResetSaveBlock(saveblock);
- (saveblock->resulthandler)(Shell_Save102_RECEIVERFAILED, saveblock->ref);
- return TRUE;
- }
-
- if(msg->header.action == message_DATALOADACK)
- {
- /* everything OK */
- Shell_Save102__ResetSaveBlock(saveblock);
- if(saveblock->flags.data.quit_after_save)
- Shell_Save102__CloseMenuOrSaveWindow(saveblock);
-
- (saveblock->resulthandler)(Shell_Save102_SAVEOK, saveblock->ref);
- return TRUE;
- }
-
- if(msg->header.action == message_DATALOAD)
- {
- /* This is our message being returned to us by the Wimp */
- Error_Report(0, "Received DATALOAD back - scrap file not loaded...");
- Shell_Save102__ResetSaveBlock(saveblock);
-
- (saveblock->resulthandler)(Shell_Save102_RECEIVERFAILED, saveblock->ref);
- return TRUE;
- }
-
- return FALSE;
- }
-
-
- static void Shell_Save102__DefaultResultHandler(Shell_Save102_result result, void *ref)
- {
- UNUSED_ARG(ref);
-
- switch(result)
- {
- case Shell_Save102_RECEIVERFAILED:
- Error_Report(0, "Receiver failed to load scrap file");
- break;
-
- case Shell_Save102_FILESAVERFAILED:
- Error_Report(0, "Filer-saver failed");
- break;
-
- case Shell_Save102_RAMSAVERFAILED:
- Error_Report(0, "RAM-saver failed");
- break;
- }
- }
-
-
- typedef BOOL (*Shell_Save102_eventclaimorreleasefn)(event_type eventtype,
- window_handle window,
- icon_handle icon,
- event_handler handler,
- void *reference);
- /* This just defines a function pointer which can point
- * to the two functions Event_Claim and Event_Release.
- */
-
-
- static void Shell_Save102__EventClaimOrRelease(Shell_Save102_saveblock *saveblock,
- Shell_Save102_eventclaimorreleasefn fn)
- {
- if(saveblock->dragsprite >= 0)
- {
- (fn)(event_CLICK, saveblock->window, saveblock->dragsprite,
- Shell_Save102__DragIconClickHandler, saveblock);
-
- (fn)(event_USERDRAG, event_ANY, event_ANY,
- Shell_Save102__UserDragHandler, saveblock);
- }
-
- if(saveblock->okbutton >= 0)
- (fn)(event_CLICK, saveblock->window, saveblock->okbutton,
- Shell_Save102__OKIconHandler, saveblock);
-
- if(saveblock->cancelbutton >= 0)
- (fn)(event_CLICK, saveblock->window, saveblock->cancelbutton,
- Shell_Save102__CancelIconHandler, saveblock);
-
- (fn)(event_KEY, saveblock->window, saveblock->filenameicon,
- Shell_Save102__KeyHandler, saveblock);
-
- (fn)(event_CLOSE, saveblock->window, event_ANY,
- Shell_Save102__MenusDeletedOrWindowClosedHandler, saveblock);
-
- (fn)(event_SEND, event_ANY, event_ANY,
- Shell_Save102__MenusDeletedOrWindowClosedHandler, saveblock);
-
- /* we always want to check whether to release the handlers
- * when a menu has been closed because flags.data.is_menu
- * may be changed after Save_InitSaveWindowHandler
- */
-
- (fn)(event_SEND, event_ANY, event_ANY, Shell_Save102__MessageHandler, saveblock);
- (fn)(event_SENDWANTACK, event_ANY, event_ANY,
- Shell_Save102__MessageHandler, saveblock);
- (fn)(event_ACK, event_ANY, event_ANY, Shell_Save102__MessageHandler, saveblock);
- }
-
-
-
- Shell_Save102_saveblock *Shell_Save102_InitSaveWindowHandler(window_handle window,
- BOOL is_menu,
- BOOL is_save_window,
- BOOL release_after,
- icon_handle dragsprite,
- icon_handle okbutton,
- icon_handle cancelbutton,
- icon_handle filenameicon,
- Shell_Save102_filesaver filesaver,
- Shell_Save102_ramsaver ramsaver,
- Shell_Save102_resulthandler resulthandler,
- size_t estimatedsize,
- int filetype,
- void *ref)
- {
- Shell_Save102_saveblock *saveblock;
-
- if(!filesaver)
- {
- /* Must have a file-saver */
- Error_Report(0, "Shell_Save102_InitSaveWindowHandler called with NULL filesaver");
- return NULL;
- }
-
- saveblock = malloc(sizeof(Shell_Save102_saveblock));
- if(!saveblock)
- {
- Error_OutOfMemory(FALSE, "save window");
- return NULL;
- }
-
- saveblock->window = window;
- saveblock->flags.data.is_menu = is_menu;
- saveblock->flags.data.is_save_window = is_save_window;
- saveblock->flags.data.release_after = release_after;
- saveblock->dragsprite = dragsprite;
- saveblock->okbutton = okbutton;
- saveblock->cancelbutton = cancelbutton;
- saveblock->filenameicon = filenameicon;
- saveblock->filesaver = filesaver;
- saveblock->ramsaver = ramsaver;
- saveblock->resulthandler = resulthandler;
- saveblock->estimatedsize = estimatedsize;
- saveblock->ref = ref;
-
- Shell_Save102_SetFiletype(saveblock, filetype);
-
- Shell_Save102__ResetSaveBlock(saveblock);
-
- if(saveblock->resulthandler == NULL)
- saveblock->resulthandler = Shell_Save102__DefaultResultHandler;
-
- Shell_Save102__CleanIconText(saveblock->window, saveblock->filenameicon);
- /* Make sure the terminator of the filename is '\0' - templates
- * seem to come with a '\n' as terminator.
- */
-
- Shell_Save102__EventClaimOrRelease(saveblock, Event_Claim);
-
- return saveblock;
- }
-
-
- void Shell_Save102_ReleaseSaveHandlers(Shell_Save102_saveblock *saveblock)
- {
- Shell_Save102__EventClaimOrRelease(saveblock, Event_Release);
- }
-